/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pt.iasd.youthshelter.honor;

import java.io.IOException;
import java.util.Collection;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.spi.actions.AbstractSavable;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.UndoRedo;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.windows.TopComponent;
import org.openide.util.lookup.InstanceContent;
import pt.iasd.youthshelter.datamodel.Honor;
import pt.iasd.youthshelter.datamodel.service.HonorController;

/**
 * Top component which displays something.
 */
//@ConvertAsProperties(
//        dtd = "-//pt.iasd.youthshelter.honor//HonorEditor//EN",
//        autostore = false)
@TopComponent.Description(
        preferredID = "HonorEditorTopComponent",
        //iconBase="SET/PATH/TO/ICON/HERE", 
        persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "editor", openAtStartup = false)
//@ActionID(category = "Window", id = "pt.iasd.youthshelter.honor.HonorEditorTopComponent")
//@ActionReference(path = "Menu/File/New" /*, position = 333 */)
//@TopComponent.OpenActionRegistration(
//        displayName = "#CTL_HonorEditorAction"/*,
//        preferredID = "HonorEditorTopComponent"*/)
//@Messages({
//    "CTL_HonorEditorAction=Honor",
////    "CTL_HonorEditorTopComponent=New honor",
////    "HINT_HonorEditorTopComponent=Honor editor window."
//})
public final class HonorEditorTopComponent extends TopComponent {
    private static final ResourceBundle bundle = java.util.ResourceBundle.getBundle("pt/iasd/youthshelter/honor/Bundle");
    
    private static final String TAG_BOLD_START = "<b>";
    private static final String TAG_BOLD_END = "</b>";
    private static final String TAG_HTML_START = "<html>";
    private static final String TAG_HTML_END = "</html>";
    
    private UndoRedo.Manager undoRedoManager = new UndoRedo.Manager();
    private InstanceContent instanceContent = new InstanceContent();
    private HonorSavable savable = new HonorSavable();
    
    /* Hidden Honor atribute. */
//    private Honor tmphonor = null;
    
    /* Hidden bean creation flag. */
    private boolean create = false;
    
    /* Logging object. */
    private Logger logger = Logger.getLogger(this.getClass().getName());
    
    public HonorEditorTopComponent(String honorName) {
        initComponents();
        create = true;
        this.honor = new Honor();
        honor.setName(honorName);
        this.NameTextField.setText(honorName);
        setName(String.format("%s%s%s%s%s", TAG_HTML_START, TAG_BOLD_START,
                        honorName, TAG_BOLD_END, TAG_HTML_END));
        setToolTipText(bundle.getString("HonorEditorTopComponent.Hint"));
        putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, Boolean.TRUE);
    }

    public HonorEditorTopComponent(Honor honor) {
        initComponents();
//        associateLookup(new AbstractLookup(instanceContent));
        create = (honor == null);
        if(create) {
            this.honor = new Honor();
            setName(String.format("%s%s%s%s%s", TAG_HTML_START, TAG_BOLD_START,
                        getDefaultName(), TAG_BOLD_END, TAG_HTML_END));
            setName(getDefaultName());
        } else {
            setName(honor.getName());
            this.honor = honor;
            undoRedoManager.discardAllEdits();
            valuesChanged();
        }
        setToolTipText(bundle.getString("HonorEditorTopComponent.Hint"));
        putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, Boolean.TRUE);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        honor = new pt.iasd.youthshelter.datamodel.Honor();
        NameLabel = new javax.swing.JLabel();
        NameTextField = new javax.swing.JTextField();
        DescriptionScrollPane = new javax.swing.JScrollPane();
        DescriptionTextArea = new javax.swing.JTextArea();

        org.openide.awt.Mnemonics.setLocalizedText(NameLabel, bundle.getString("HonorEditorTopComponent.NameLabel.text"));

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, honor, org.jdesktop.beansbinding.ELProperty.create("${name}"), NameTextField, org.jdesktop.beansbinding.BeanProperty.create("text"), "NameBinding");
        bindingGroup.addBinding(binding);

        NameTextField.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                NameTextFieldKeyReleased(evt);
            }
        });

        DescriptionTextArea.setColumns(20);
        DescriptionTextArea.setRows(5);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, honor, org.jdesktop.beansbinding.ELProperty.create("${description}"), DescriptionTextArea, org.jdesktop.beansbinding.BeanProperty.create("text"), "DescriptionBinding");
        bindingGroup.addBinding(binding);

        DescriptionTextArea.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                DescriptionTextAreaKeyReleased(evt);
            }
        });
        DescriptionScrollPane.setViewportView(DescriptionTextArea);
        DescriptionTextArea.getDocument().addUndoableEditListener(undoRedoManager);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(DescriptionScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 602, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(NameLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(NameTextField)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(NameLabel)
                    .addComponent(NameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(DescriptionScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE)
                .addContainerGap())
        );

        NameTextField.getDocument().addUndoableEditListener(undoRedoManager);

        bindingGroup.bind();
    }// </editor-fold>//GEN-END:initComponents

    private void NameTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_NameTextFieldKeyReleased
        valuesChanged();
    }//GEN-LAST:event_NameTextFieldKeyReleased

    private void DescriptionTextAreaKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_DescriptionTextAreaKeyReleased
        valuesChanged();
    }//GEN-LAST:event_DescriptionTextAreaKeyReleased

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane DescriptionScrollPane;
    private javax.swing.JTextArea DescriptionTextArea;
    private javax.swing.JLabel NameLabel;
    private javax.swing.JTextField NameTextField;
    private pt.iasd.youthshelter.datamodel.Honor honor;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables
    
    @Override
    public boolean canClose() {
        Collection<? extends HonorSavable> savables = getLookup().lookupAll(HonorSavable.class);
        if(savables != null && savables.contains(savable)) {
            NotifyDescriptor.Confirmation confirm = new NotifyDescriptor.Confirmation(
                    bundle.getString("Confirmation.Editor.Message")
                        .replace("\n", System.getProperty("line.separator")),
                    bundle.getString("Confirmation.Editor.Title")
            );
            Object option = DialogDisplayer.getDefault().notify(confirm);
            if(option == NotifyDescriptor.YES_OPTION) {
                getLookup().lookup(HonorSavable.class).handleSave();
                return true;
            } else if(option == NotifyDescriptor.NO_OPTION) {
                savable.cancelSave();
                return true;
            } else {
                return false;
            }
        } else {
            return true;
        }
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // read your settings according to their version
    }
    
    private void valuesChanged() {
        if(undoRedoManager.canUndo()) {
            if(getLookup().lookup(HonorSavable.class) == null) {
                instanceContent.remove(savable);
                instanceContent.add(savable);
            }
            setName(String.format("%s%s%s%s%s", TAG_HTML_START, TAG_BOLD_START,
                    (NameTextField.getText().isEmpty())? getName() : NameTextField.getText(),
                    TAG_BOLD_END, TAG_HTML_END));
        } else {
//            HonorSavable savable = getLookup().lookup(HonorSavable.class);
//            if(savable != null) {
                instanceContent.remove(savable);
//            }
            setName(((NameTextField.getText().isEmpty())? getDefaultName() : NameTextField.getText()));
        }
    }

    @Override
    public UndoRedo getUndoRedo() {
        return undoRedoManager;
    }
    
    private String getDefaultName() {
        return bundle.getString("HonorEditorTopComponent.Title");
    }
    
    // <editor-fold defaultstate="collapsed" desc="Inner Classes">
    private class HonorSavable extends AbstractSavable {
        public HonorSavable() {
            register();
        }
        
        public void cancelSave() {
            instanceContent.remove(this);
            unregister();
        }
        
        @Override
        protected String findDisplayName() {
            return getName();
        }

        @Override
        protected void handleSave() {
            /* Check not null requirements */
            if(NameTextField.getText() == null || NameTextField.getText().isEmpty()) {
                NotifyDescriptor.Message alert = new NotifyDescriptor.Message(
                        bundle.getString("NoHonorName.Error")
                                .replace("\n", System.getProperty("line.separator")),
                        NotifyDescriptor.ERROR_MESSAGE);
                DialogDisplayer.getDefault().notify(alert);
                return;
            }
            
            /* Create progress bar handle */
            ProgressHandle pHandle = ProgressHandleFactory.createHandle(
                    bundle.getString("ProgressBarSave"));
            pHandle.start(3);
            
            /* Set honor parameters. */
            honor.setName(NameTextField.getText());
            String description = DescriptionTextArea.getText();
            if(description != null && !description.isEmpty()) {
                honor.setDescription(description);
            }
            pHandle.progress(1);
            
            /* Persist honor in database. */
            HonorController controller = Lookup.getDefault().lookup(HonorController.class);
            if(controller != null) {
                try{
                    if(create) {
                        controller.create(honor);
                    } else {
                        controller.edit(honor);
                    }
                } catch(Exception ex) {
                    logger.log(Level.WARNING, ex.getLocalizedMessage(), ex);
                }
            }
            pHandle.progress(1);
            
            /* Remove this savable from lookup. */
            instanceContent.remove(this);
            setName(honor.getName());
            unregister();
            HonorListTopComponent.loadHonorListData();
            pHandle.progress(1);
            pHandle.finish();
        }

        @Override
        public boolean equals(Object o) {
            if(o instanceof HonorSavable) {
                return this == (HonorSavable) o;
            }
            return false;
        }

        @Override
        public int hashCode() {
            return HonorEditorTopComponent.this.hashCode();
        }
    }// </editor-fold>
}
